package com.example.demo.game;

import com.example.demo.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Wukong
 * Date: 2023-04-24
 * Time: 20:29
 */

    @Component
    public class Matcher {
    @Autowired
    private RoomManager roomManager;
    @Autowired
    private OnlineUserManager onlineUserManager;
    //将 Java 对象转换为 JSON 字符串（序列化）。
    //将 JSON 字符串转换为 Java 对象（反序列化）
    private ObjectMapper objectMapper = new ObjectMapper();

    //使用 LinkedList 作为匹配队列
    private Queue<User> normalQueue = new LinkedList<>();
    private Queue<User> highQueue = new LinkedList<>();
    private Queue<User> veryHighQueue = new LinkedList<>();


    /**
     * 启动三个匹配线程，分别处理不同分数段的队列
     * */
    private Matcher() {
       //使用内部匿名线程为每个队列（普通、高级、顶级）创建独立的线程，实现并行匹配，避免不同分数段玩家相互阻塞。
     //使用while (true)循环确保线程持续运行，不断从队列中取出玩家进行匹配
        new Thread() {
            @Override
            public void run() {
                while (true) {
                    handlerMatch(normalQueue);
                }
            }
        }.start();

        new Thread() {
            @Override
            public void run() {
                while (true) {
                    handlerMatch(highQueue);
                }
            }
        }.start();

        new Thread() {
            @Override
            public void run() {
                while (true) {
                    handlerMatch(veryHighQueue);
                }
            }
        }.start();
    }
   /**
    * 从队列中取出两个玩家进行匹配，并将匹配成功的玩家放入游戏房间。
    * */
    private void handlerMatch(Queue<User> matchQueue) {
        //使用synchronized确保同一时间只有一个线程操作队列
        synchronized (matchQueue) {
            try {
          //当队列中玩家数量不足 2 时，调用matchQueue.wait()使线程进入等待状态，避免无效循环
                while (matchQueue.size() < 2) {
                    matchQueue.wait();
                }
                // 1.从队列中取出两个玩家
                User player1 = matchQueue.poll();
                User player2 = matchQueue.poll();
                System.out.println("匹配出两个玩家: " + player1.getUserId() + ", " + player2.getUserId());
                // 2. 检查玩家在线状态(可能在匹配中玩家突然关闭页面)
                WebSocketSession session1 = onlineUserManager.getSessionFromGameHall(player1.getUserId());
                WebSocketSession session2 = onlineUserManager.getSessionFromGameHall(player2.getUserId());
                if (session1 == null) {
                    // 如果玩家1 下线, 则把玩家2 放回匹配队列
                    matchQueue.offer(player2);
                    return;
                }
                if (session2 == null) {
                    // 如果玩家2 下线, 则把玩家1 放回匹配队列
                    matchQueue.offer(player1);
                    return;
                }
                if (session1 == session2) {
                    // 如果得到的两个 session 相同, 说明是同一个玩家两次进入匹配队列
                    // 例如玩家点击开始匹配后, 刷新页面, 重新再点开始匹配
                    // 此时也把玩家放回匹配队列
                    matchQueue.offer(player1);
                    return;
                }

                // 3. 将这两个玩家加入到游戏房间中.
                // TODO 一会再写
                Room room = new Room();
                roomManager.addRoom(room, player1.getUserId(), player2.getUserId());

                // 4. 给玩家1 发回响应数据
                MatchResponse response1 = new MatchResponse();
                response1.setMessage("matchSuccess");
                session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(response1)));
                // 5. 给玩家2 发回响应数据
                MatchResponse response2 = new MatchResponse();
                response2.setMessage("matchSuccess");
                session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(response2)));
            } catch (InterruptedException | IOException e) {
                e.printStackTrace();
            }
        }
    }

  /**
   * 玩家根据分数进入不同匹配队列
   * */
  //同步机制和唤醒机制
  //使用 synchronized 锁定队列对象，确保同一时间只有一个线程能修改队列
  //notify() 唤醒可能正在等待该队列的匹配线程
    public void add(User user) throws InterruptedException {
        if (user.getScore() < 2000) {
            synchronized (normalQueue) {
                normalQueue.offer(user);
                normalQueue.notify();
            }
            System.out.println("[Matcher] " + user.getUserId() + " 进入 normalQueue!");
        } else if (user.getScore() < 3000) {
            synchronized (highQueue) {
                highQueue.offer(user);
                highQueue.notify();
            }
            System.out.println("[Matcher] " + user.getUserId() + " 进入 highQueue!");
        } else {
            synchronized (veryHighQueue) {
                veryHighQueue.offer(user);
                veryHighQueue.notify();
            }
            System.out.println("[Matcher] " + user.getUserId() + " 进入 veryHighQueue!");
        }
    }

        public void remove(User user) {
            if (user.getScore() < 2000) {
                removeFromQueue(normalQueue, user);
                System.out.println("[Matcher] " + user.getUserId() + " 移出 normalQueue!");
            } else if (user.getScore() < 3000) {
                removeFromQueue(highQueue, user);
                System.out.println("[Matcher] " + user.getUserId() + " 移出 highQueue!");
            } else {
                removeFromQueue(veryHighQueue, user);
                System.out.println("[Matcher] " + user.getUserId() + " 移出 veryHighQueue!");
            }
        }
    private void removeFromQueue(Queue<User> queue, User user) {
        synchronized (queue) {
            queue.remove(user);
        }
    }



    }


